package com.newegg.research;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.logging.Logger;

import org.apache.commons.io.FileUtils;

import com.newegg.research.datastructure.Heap;
import com.newegg.research.tfidfAnalyzer.Category;
import com.newegg.research.tfidfAnalyzer.Indexer;
import com.newegg.research.tfidfAnalyzer.Token;

public class FeatureMapping
{
	static Logger logger = Logger.getLogger(FeatureMapping.class.getName());

	Indexer indexer = new Indexer();

	StringTokenizer tokenizer = new StringTokenizer();

	protected Set<String> all_categorys;

	public void removeIndex(String word)
	{
		indexer.removeIndex(word);
	}

	public List<String> analysisValueViaNaiveBayes(String s,final int num)
	{
		List<String> tokens = tokenizer.participle(s);
		List<Token> l = new ArrayList<Token>(tokens.size());
		for (String t : tokens)
		{
			Token to = indexer.getToken(t, false);
			if (to != null)
				l.add(to);
			else
				logger.warning("无效查询词：" + t);
		}
		List<Category> cs = indexer.getAllCategory();
		Heap heap = new Heap(cs.size());
		int all_token_num = indexer.getAllTokens().size();
		for (Category c : cs)
		{
			float result = 0;
			for (Token t : l)
			{
				int tf = t.getCountInCategory(c);
				int cf = t.getSumCount();
				if (tf == 0 || cf == 0)
					continue;

				if (tf > 0)
					result += Math.log(tf + 1) - Math.log(cf + all_token_num);
			}
			result += Math.log(c.getTokenCount())
					- Math.log(indexer.getAllTokenNum());
			if (result != 0)
				heap.insert(c, result);
		}
		
		int size = heap.size() > num ? num : heap.size();
		List <String> result = new ArrayList<String>(size);
		if (heap.isEmpty())
			return result;
		else
		{
			int count = 0;
			for(;count < size ;count++)
			{
				result.add(heap.remove().toString());
			}
			return result;
		}
	}

	@SuppressWarnings("unchecked")
	public void init(String trainingFile) throws IOException
	{
		logger.info("Index the training file:" + trainingFile
				+ ", please wait for a while");
		long start = System.currentTimeMillis();
		Iterator<String> it = FileUtils.lineIterator(new File(trainingFile));
		while (it.hasNext())
		{
			String line = it.next();
			String[] params = line.split("\\$");
			if (params.length == 3)
			{
				String name = params[0];
				String value = params[1];
				String repeat = params[2];
				addIndex(name, value, repeat);
			} else
			{
				logger.warning("The bad formatted content:" + line);
			}
		}

		filterTokens();
		all_categorys = indexer.getAllCategoriesAsMap().keySet();
		logger.info("The " + indexer.getAllTokenNum() + " tokens was indexed.");
		logger.info("The " + indexer.getAllCategoriesAsMap().size()
				+ " category was also indexed.");
		logger.info("Index is finished, takes "
				+ (System.currentTimeMillis() - start) + "ms");
	}

	protected void addIndex(String name, String value, String repeat)
	{
		int repeats = Integer.parseInt(repeat);
		List<String> words = tokenizer.participle(value);
		for (int i = 0; i < repeats; i++)
		{
			for (String s : words)
			{
				indexer.index(s, name);
			}
		}
	}

	public int analysisName(String standard_name, String input_name)
	{
		Object[] o = StringUtil.getMaxSubString(standard_name, input_name,
				false);
		int a = (Integer) o[0];
		// float b = (Float) o[1];
		return a;

	}

	public void filterTokens()
	{
		List<Token> tokens = indexer.getAllTokens();
		Heap heap = new Heap(tokens.size());
		for (Token t : tokens)
		{
			heap.insert(t, 100 - (float) getIndexer().calcIDF(t));
		}
		int count = 0;
		while (!heap.isEmpty())
		{
			Heap.Entry entry = heap.removeEntry();
			if (entry.getValue().toString().length() < 2)
			{
				removeIndex(entry.getValue().toString());
				count++;
			}
		}
		logger.info(count + " words has been removed by the filter");
	}

	public String guess(String categoryName, String value)
	{
		if (categoryName.length() > 3 && all_categorys.contains(categoryName))
		{
			logger.info("===== @@@ 使用完全类别名匹配 =====");
			return categoryName;
		}
//		List<String> value_guess_result = analysisValue(value, 10);
		List<String> value_guess_result = analysisValueViaNaiveBayes(value, 10);
		Heap heap = new Heap(value_guess_result.size());
		for (String s : value_guess_result)
		{
			heap.insert(s, analysisName(s, categoryName));
		}
		Heap.Entry entry = heap.removeEntry();
		if (entry != null && entry.getPriority() > 10)
		{
			logger.info("===== @@@ 使用类别名称匹配, 匹配度:" + entry.getPriority()
					+ "=====");
			return (String) entry.getValue();
		} else if (value_guess_result.size() > 0)
		{
			logger.info("===== @@@ 使用参数值匹配 =====");
			return value_guess_result.get(0);
		} else
		{
			logger.info("===== ### 无法通过Value进行匹配，尝试使用Name进行匹配 =====");
			System.out.println(categoryName + ":" + value);
			return null;
		}
	}

	public List<String> analysisValue(String s, int num)
	{
		List<String> result = new ArrayList<String>(num);
		List<String> tokens = tokenizer.participle(s);
		List<Token> l = new ArrayList<Token>(tokens.size());
		for (String t : tokens)
		{
			Token to = indexer.getToken(t, false);
			if (to != null)
				l.add(to);
			else
				logger.warning("无效查询词：" + t);
		}
		List<Category> cs = indexer.getAllCategory();
		Heap heap = new Heap(cs.size());
		for (Category c : cs)
		{
			double d = indexer.acos(l, c, null);
			if (d < 1)
				heap.insert(c, 0 - (float) d);
		}
		int count = 0;
		while (!heap.isEmpty())
		{
			if (count++ < num)
				result.add(heap.remove().toString());
			else
				break;
		}
		return result;
	}

	public static void main(String[] args) throws IOException
	{
		FeatureMapping mapping = new FeatureMapping();
		mapping.init("data/analysis_result.txt");
		Scanner scanner = new Scanner(System.in);
		String line = null;
		// List<Category> cs = mapping.indexer.getAllCategory();
		while ((line = scanner.nextLine()) != null)
		{
			String[] x = line.split("\\$");
			if (x.length == 2)
				System.out.println(mapping.guess(x[0], x[1]));
			else
				System.out.println("Error");
		}
	}

	public Indexer getIndexer()
	{
		return indexer;
	}

}
